#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "driver/spi_master.h"
#include "driver/gpio.h"
#include "esp_timer.h"

#define PRINTER_SPI_HOST    SPI2_HOST

#define PIN_NUM_MISO -1
#define PIN_NUM_MOSI 15
#define PIN_NUM_CLK  16
#define PIN_NUM_CS   -1

#define PIN_NUM_LAT GPIO_NUM_13 
#define PIN_NUM_VH GPIO_NUM_14

#define PIN_NUM_STB1 GPIO_NUM_6
#define PIN_NUM_STB2 GPIO_NUM_5
#define PIN_NUM_STB3 GPIO_NUM_4
#define PIN_NUM_STB4 GPIO_NUM_3
#define PIN_NUM_STB5 GPIO_NUM_2
#define PIN_NUM_STB6 GPIO_NUM_1

uint8_t pin_stbs[] = {  
                    PIN_NUM_STB1,PIN_NUM_STB2,PIN_NUM_STB3,
                    PIN_NUM_STB4,PIN_NUM_STB5,PIN_NUM_STB6
                };

static spi_device_handle_t spi_handle;
void init_printer_spi(){
    esp_err_t ret;
    
    spi_bus_config_t buscfg = {
        .miso_io_num = PIN_NUM_MISO,
        .mosi_io_num = PIN_NUM_MOSI,
        .sclk_io_num = PIN_NUM_CLK,
        .quadwp_io_num = -1,
        .quadhd_io_num = -1,
        .max_transfer_sz = 48
    };
    spi_device_interface_config_t devcfg = {

        .clock_speed_hz = 2 * 1000 * 1000,     //Clock out at 26 MHz
        .mode = 0,                              //SPI mode 0
        .spics_io_num = PIN_NUM_CS,             //CS pin
        .queue_size = 7,                        //We want to be able to queue 7 transactions at a time
        .pre_cb = NULL, //Specify pre-transfer callback to handle D/C line
    };
    // 初始化SPI总线
    ret = spi_bus_initialize(PRINTER_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO);
    ESP_ERROR_CHECK(ret);
    // 将打印机相关配置添加到SPI
    ret = spi_bus_add_device(PRINTER_SPI_HOST, &devcfg, &spi_handle);
    ESP_ERROR_CHECK(ret);
}

static void init_vh(){
    gpio_config_t vh_gpio_config = {
        .mode = GPIO_MODE_OUTPUT,
        .pin_bit_mask = 1ULL << PIN_NUM_VH
    };
    ESP_ERROR_CHECK(gpio_config(&vh_gpio_config));

    gpio_set_level(PIN_NUM_VH,0);
}

static void init_lat(){
    gpio_config_t lat_gpio_config = {
        .mode = GPIO_MODE_OUTPUT,
        .pin_bit_mask = 1ULL << PIN_NUM_LAT
    };
    ESP_ERROR_CHECK(gpio_config(&lat_gpio_config));

    gpio_set_level(PIN_NUM_LAT,1);
}

void init_stbs(){
    gpio_config_t stb_gpio_config = {
        .mode = GPIO_MODE_OUTPUT,
        .pin_bit_mask = (1ULL << PIN_NUM_STB1)|(1ULL << PIN_NUM_STB2)|(1ULL << PIN_NUM_STB3)|(1ULL << PIN_NUM_STB4)|(1ULL << PIN_NUM_STB5)|(1ULL << PIN_NUM_STB6)
    };
    ESP_ERROR_CHECK(gpio_config(&stb_gpio_config));

    for (size_t i = 0; i < 6; i++)
    {
        gpio_set_level(pin_stbs[i],0);
    }

}

void print_one_line(uint8_t* data){
    esp_err_t ret;
    spi_transaction_t t;
    
    memset(&t, 0, sizeof(t));       //Zero out the transaction
    uint8_t len = 48;
    t.length = len * 8;             //Len is in bytes, transaction length is in bits.
    t.tx_buffer = data;             //Data
    ret = spi_device_transmit(spi_handle, &t); //Transmit!
    assert(ret == ESP_OK);
    
    // 数据锁存
    gpio_set_level(PIN_NUM_LAT,0);
    esp_rom_delay_us(1); 
    gpio_set_level(PIN_NUM_LAT,1);
    // 加热头一次工作
    for (size_t i = 0; i < 6; i++)
    {
        gpio_set_level(pin_stbs[i],1);
        esp_rom_delay_us(2000); 
        gpio_set_level(pin_stbs[i],0);
        esp_rom_delay_us(20);
    }
}


void example_printer_one_line_main(void)
{
    // 初始化SPI总线
    init_printer_spi();
    // 初始化锁存器
    init_lat();
    // 初始化STB加热头
    init_stbs();
    // 初始化加热头总开关
    init_vh();

    ////////////////////演示打印一行数据//////////////////////////
    // 打开总开关
    gpio_set_level(PIN_NUM_VH,1);
    
    // 发送一行数据
    uint8_t data[48];
    memset(data, 0xff, sizeof(data));
    print_one_line(data);
    //关闭总开关
    gpio_set_level(PIN_NUM_VH,0);
    printf("测试打印完成\r\n");
}


void example_printer_multi_line_main(void){
    // 初始化SPI总线
    init_printer_spi();
    // 初始化锁存器
    init_lat();
    // 初始化STB加热头
    init_stbs();
    // 初始化加热头总开关
    init_vh();
    // 初始化步进电机
    extern void bsp_step_init();
    bsp_step_init();

    // 准备测试数据
    uint8_t data[48];
    memset(data, 0xff, sizeof(data));

    
    // 打开总开关
    gpio_set_level(PIN_NUM_VH,1);
    extern void bsp_step_move_steps(uint16_t steps);
    // 发送一行数据
    for (size_t i = 0; i < 40; i++)
    {
        print_one_line(data);
        // 移动4步
        bsp_step_move_steps(4);
    }
    
    bsp_step_move_steps(80);
    // 记得打印完停止电机供电，防止发热
    extern void bsp_step_stop();
    bsp_step_stop();
    //关闭总开关
    gpio_set_level(PIN_NUM_VH,0);
    printf("测试打印完成\r\n");
}